package org.spamforces.utils;

import com.codeforces.commons.io.http.HttpResponse;
import com.codeforces.commons.io.http.HttpUtil;
import org.spamforces.model.Recipient;
import org.spamforces.model.RecipientProvider;

import javax.xml.stream.*;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.URL;
import java.util.HashMap;
import java.util.Map;
import java.util.regex.Pattern;

public class XMLHelper {
    private static final Pattern EMAIL_REGEXP = Pattern.compile("[A-Z0-9._%+-]+@[A-Z0-9.-]+\\.[A-Z]{2,6}");

    public static Map<Recipient, Map<String, String>> processXML(InputStream stream)
            throws XMLStreamException, FactoryConfigurationError {
        XMLStreamReader reader = XMLInputFactory.newInstance().createXMLStreamReader(stream);
        Map<Recipient, Map<String, String>> paramValueByKeyByRecipient = new HashMap<>();

        while (reader.hasNext()) {
            int event = reader.next();

            if (event == XMLStreamConstants.START_ELEMENT && "emails".equals(reader.getLocalName())) {
                event = reader.nextTag();

                while (event != XMLStreamConstants.END_ELEMENT || !"emails".equals(reader.getLocalName())) {
                    if (event == XMLStreamConstants.START_ELEMENT && "email".equals(reader.getLocalName())) {
                        Map<String, String> paramValueByKey = new HashMap<>();
                        int attributeCount = reader.getAttributeCount();
                        Recipient recipient = new Recipient();

                        for (int i = 0; i < attributeCount; ++i) {
                            String key = reader.getAttributeLocalName(i);
                            String value = reader.getAttributeValue(i);
                            paramValueByKey.put(key, value);

                            if ("address".equals(key) || "email".equals(key)) {
                                paramValueByKey.put("address", value);
                                paramValueByKey.put("email", value);
                                recipient.setEmail(value);
                            }
                        }

                        if (EMAIL_REGEXP.matcher(recipient.getEmail().toUpperCase()).matches()) {
                            paramValueByKeyByRecipient.put(recipient, paramValueByKey);
                        }

                        event = reader.nextTag();
                        while (event != XMLStreamConstants.END_ELEMENT && "email".equals(reader.getLocalName())) {
                            event = reader.nextTag();
                        }
                    }

                    event = reader.nextTag();
                }
            } else if (event == XMLStreamConstants.START_ELEMENT && "recipients".equals(reader.getLocalName())) {
                event = reader.nextTag();

                while (event != XMLStreamConstants.END_ELEMENT || !"recipients".equals(reader.getLocalName())) {
                    if (event == XMLStreamConstants.START_ELEMENT && "recipient".equals(reader.getLocalName())) {
                        Map<String, String> paramValueByKey = new HashMap<>();
                        int attributeCount = reader.getAttributeCount();
                        Recipient recipient = new Recipient();

                        for (int i = 0; i < attributeCount; ++i) {
                            String key = reader.getAttributeLocalName(i);
                            String value = reader.getAttributeValue(i);
                            paramValueByKey.put(key, value);

                            if (("address".equals(key) || "email".equals(key))
                                    && EMAIL_REGEXP.matcher(value.toUpperCase()).matches()) {
                                paramValueByKey.put("address", value);
                                paramValueByKey.put("email", value);
                                recipient.setEmail(value);
                            } else if ("phone".equals(key) && SmsUtil.checkPhone(value)) {
                                recipient.setPhone(value);
                            }
                        }

                        if (recipient.getEmail() != null || recipient.getPhone() != null) {
                            paramValueByKeyByRecipient.put(recipient, paramValueByKey);
                        }

                        event = reader.nextTag();
                        while (event != XMLStreamConstants.END_ELEMENT && "recipient".equals(reader.getLocalName())) {
                            event = reader.nextTag();
                        }
                    }

                    event = reader.nextTag();
                }
            }
        }

        return paramValueByKeyByRecipient;
    }

    public static Map<Recipient, Map<String, String>> processXML(RecipientProvider provider)
            throws XMLStreamException, FactoryConfigurationError, IOException {
        URL url = new URL(provider.getUrl() + "?login=" + provider.getLogin() + "&password=" + provider.getPassword());

        HttpResponse response = HttpUtil.executePostRequestAndReturnResponse(url.toExternalForm());
        if (response.hasIoException() || response.getCode() == -1 || response.getBytes() == null) {
            if (response.hasIoException()) {
                throw new IOException("Got unexpected " + response + " from e-mail provider.", response.getIoException());
            } else {
                throw new IOException("Got unexpected " + response + " from e-mail provider.");
            }
        }

        return processXML(new ByteArrayInputStream(response.getBytes()));
    }
}
